using CoreManager.Repository.Repositories;
using CoreManager.Models.DTOs;
using Microsoft.Extensions.Logging;
using AutoMapper;
using CoreManager.Services.Menus;
using CoreManager.Models.Entities;
using Microsoft.EntityFrameworkCore;

namespace CoreManager.Services
{
    /// <summary>
    /// 菜单服务实现
    /// </summary>
    public class MenuService : IMenuService
    {
        private readonly IRepository<Menu> _menuRepository;
        private readonly IRepository<UserRole> _userRoleRepository;
        private readonly IRepository<RoleMenu> _roleMenuRepository;
        private readonly ILogger<MenuService> _logger;
        private readonly IMapper _mapper;

        public MenuService(
            IRepository<Menu> menuRepository, 
            IRepository<UserRole> userRoleRepository,
            IRepository<RoleMenu> roleMenuRepository,
            ILogger<MenuService> logger, 
            IMapper mapper)
        {
            _menuRepository = menuRepository;
            _userRoleRepository = userRoleRepository;
            _roleMenuRepository = roleMenuRepository;
            _logger = logger;
            _mapper = mapper;
        }

        /// <summary>
        /// 根据Key更新菜单
        /// </summary>
        /// <param name="key">菜单Key</param>
        /// <param name="updateDto">更新菜单DTO</param>
        /// <returns></returns>
        public async Task<ApiResponse<MenuDto>> UpdateMenuByKeyAsync(string key, UpdateMenuDto updateDto)
        {
            try
            {
                var menu = await _menuRepository.GetAsync(m => !m.IsDeleted && m.Key == key);
                
                if (menu == null)
                {
                    return ApiResponse<MenuDto>.Fail("菜单不存在");
                }

                // 使用现有的UpdateMenuAsync方法
                return await UpdateMenuAsync(menu.Id, updateDto);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "根据Key更新菜单时发生异常，Key: {MenuKey}", key);
                return ApiResponse<MenuDto>.Fail("更新菜单失败");
            }
        }

        /// <summary>
        /// 获取菜单树
        /// </summary>
        /// <returns></returns>
        public async Task<ApiResponse<List<MenuDto>>> GetMenuTreeAsync()
        {
            try
            {
                var menus = await _menuRepository.GetListAsync(m => !m.IsDeleted);
                var sortedMenus = menus.OrderBy(m => m.Sort).ToList();
                var menuDtos = BuildMenuTree(sortedMenus);
                return ApiResponse<List<MenuDto>>.Success(menuDtos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取菜单树时发生异常");
                return ApiResponse<List<MenuDto>>.Fail("获取菜单树失败");
            }
        }

        /// <summary>
        /// 获取用户菜单
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns></returns>
        public async Task<ApiResponse<List<MenuDto>>> GetUserMenusAsync(int userId)
        {
            try
            {
                // 获取用户的角色ID列表
                var userRoleIds = await _userRoleRepository.GetQueryable()
                    .Where(ur => ur.UserId == userId && !ur.IsDeleted)
                    .Select(ur => ur.RoleId)
                    .ToListAsync();

                if (!userRoleIds.Any())
                {
                    // 如果用户没有分配角色，返回空菜单列表
                    return ApiResponse<List<MenuDto>>.Success(new List<MenuDto>());
                }

                // 根据用户角色获取菜单ID列表
                var menuIds = await _roleMenuRepository.GetQueryable()
                    .Where(rm => userRoleIds.Contains(rm.RoleId) && !rm.IsDeleted)
                    .Select(rm => rm.MenuId)
                    .Distinct()
                    .ToListAsync();

                if (!menuIds.Any())
                {
                    // 如果角色没有分配菜单权限，返回空菜单列表
                    return ApiResponse<List<MenuDto>>.Success(new List<MenuDto>());
                }

                // 获取用户有权限的菜单
                var userMenus = await _menuRepository.GetQueryable()
                    .Where(m => menuIds.Contains(m.Id) && !m.IsDeleted && m.Status == 1)
                    .OrderBy(m => m.Sort)
                    .ToListAsync();

                // 构建菜单树（包含父级菜单）
                var allMenus = await GetMenusWithParents(userMenus);
                var menuDtos = BuildMenuTree(allMenus);
                
                return ApiResponse<List<MenuDto>>.Success(menuDtos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取用户菜单时发生异常，用户ID: {UserId}", userId);
                return ApiResponse<List<MenuDto>>.Fail("获取用户菜单失败");
            }
        }

        /// <summary>
        /// 获取菜单及其所有父级菜单
        /// </summary>
        /// <param name="userMenus">用户有权限的菜单</param>
        /// <returns></returns>
        private async Task<List<Menu>> GetMenusWithParents(List<Menu> userMenus)
        {
            var allMenuIds = new HashSet<int>(userMenus.Select(m => m.Id));
            var parentIds = new HashSet<int>();

            // 收集所有需要的父级菜单ID
            foreach (var menu in userMenus)
            {
                var currentParentId = menu.ParentId;
                while (currentParentId.HasValue && currentParentId > 0)
                {
                    if (!allMenuIds.Contains(currentParentId.Value))
                    {
                        parentIds.Add(currentParentId.Value);
                        allMenuIds.Add(currentParentId.Value);
                    }

                    // 获取父级菜单的父级ID
                    var parentMenu = await _menuRepository.GetByIdAsync(currentParentId.Value);
                    currentParentId = parentMenu?.ParentId;
                }
            }

            // 获取所有父级菜单
            var parentMenus = new List<Menu>();
            if (parentIds.Any())
            {
                parentMenus = await _menuRepository.GetQueryable()
                    .Where(m => parentIds.Contains(m.Id) && !m.IsDeleted && m.Status == 1)
                    .ToListAsync();
            }

            // 合并用户菜单和父级菜单
            var allMenus = userMenus.Concat(parentMenus).ToList();
            return allMenus.OrderBy(m => m.Sort).ToList();
        }

        /// <summary>
        /// 根据ID获取菜单详情
        /// </summary>
        /// <param name="id">菜单ID</param>
        /// <returns></returns>
        public async Task<ApiResponse<MenuDto>> GetMenuByIdAsync(int id)
        {
            try
            {
                var menu = await _menuRepository.GetByIdAsync(id);
                
                if (menu == null || menu.IsDeleted)
                {
                    return ApiResponse<MenuDto>.Fail("菜单不存在");
                }

                var menuDto = MapToDto(menu);
                return ApiResponse<MenuDto>.Success(menuDto);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "根据ID获取菜单时发生异常，ID: {MenuId}", id);
                return ApiResponse<MenuDto>.Fail("获取菜单失败");
            }
        }

        /// <summary>
        /// 根据查询条件获取菜单列表
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <returns></returns>
        public async Task<ApiResponse<List<MenuDto>>> GetMenusAsync(MenuQueryDto query)
        {
            try
            {
                // 构建查询条件
                var menus = await _menuRepository.GetListAsync(m => !m.IsDeleted &&
                    (string.IsNullOrEmpty(query.Name) || m.Name.Contains(query.Name)) &&
                    (!query.Type.HasValue || m.Type == query.Type.Value) &&
                    (!query.Status.HasValue || m.Status == query.Status.Value) &&
                    (!query.ParentId.HasValue || m.ParentId == query.ParentId.Value));

                // 按排序号排序
                var sortedMenus = menus.OrderBy(m => m.Sort).ToList();
                
                // 映射为DTO
                var menuDtos = sortedMenus.Select(MapToDto).ToList();
                
                return ApiResponse<List<MenuDto>>.Success(menuDtos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "根据查询条件获取菜单列表时发生异常");
                return ApiResponse<List<MenuDto>>.Fail("获取菜单列表失败");
            }
        }

        /// <summary>
        /// 分页获取菜单列表
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="keyword">关键词</param>
        /// <returns></returns>
        public async Task<ApiResponse<PagedResponse<MenuDto>>> GetMenuPagedListAsync(int pageIndex, int pageSize, string? keyword = null)
        {
            try
            {
                var (items, total) = await _menuRepository.GetPagedListAsync(
                    m => !m.IsDeleted && (string.IsNullOrEmpty(keyword) || m.Name.Contains(keyword) || m.Key.Contains(keyword)),
                    pageIndex,
                    pageSize,
                    m => m.Sort);

                var menuDtos = items.Select(MapToDto).ToList();
                var result = new PagedResponse<MenuDto>
                {
                    Items = menuDtos,
                    Total = total,
                    PageIndex = pageIndex,
                    PageSize = pageSize
                };

                return ApiResponse<PagedResponse<MenuDto>>.Success(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "分页获取菜单列表时发生异常");
                return ApiResponse<PagedResponse<MenuDto>>.Fail("获取菜单列表失败");
            }
        }

        /// <summary>
        /// 创建菜单
        /// </summary>
        /// <param name="createMenuDto">创建菜单DTO</param>
        /// <returns></returns>
        public async Task<ApiResponse<MenuDto>> CreateMenuAsync(CreateMenuDto createMenuDto)
        {
            try
            {
                // 检查菜单Key是否已存在
                var existingMenu = await _menuRepository.GetAsync(m => m.Key == createMenuDto.Key && !m.IsDeleted);
                if (existingMenu != null)
                {
                    return ApiResponse<MenuDto>.Fail("菜单Key已存在");
                }

                // 使用AutoMapper映射
                var menu = _mapper.Map<Menu>(createMenuDto);
                menu.CreateTime = DateTime.Now;
                menu.UpdateTime = DateTime.Now;

                // 添加菜单
                var result = await _menuRepository.InsertAsync(menu);
                if (result > 0)
                {
                    var menuDto = _mapper.Map<MenuDto>(menu);
                    return ApiResponse<MenuDto>.Success(menuDto, "菜单创建成功");
                }

                return ApiResponse<MenuDto>.Fail("菜单创建失败");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建菜单时发生异常");
                return ApiResponse<MenuDto>.Fail("菜单创建失败");
            }
        }

        /// <summary>
        /// 更新菜单
        /// </summary>
        /// <param name="id">菜单ID</param>
        /// <param name="updateDto">更新菜单DTO</param>
        /// <returns></returns>
        public async Task<ApiResponse<MenuDto>> UpdateMenuAsync(int id, UpdateMenuDto updateDto)
        {
            try
            {
                var menu = await _menuRepository.GetByIdAsync(id);
                if (menu == null || menu.IsDeleted)
                {
                    return ApiResponse<MenuDto>.Fail("菜单不存在");
                }

                // 检查菜单Key是否重复
                var existingMenu = await _menuRepository.GetAsync(m => !m.IsDeleted && m.Key == updateDto.Key && m.Id != id);
                if (existingMenu != null)
                {
                    return ApiResponse<MenuDto>.Fail("菜单Key已存在");
                }

                // 检查父级菜单是否存在
                if (updateDto.ParentId.HasValue && updateDto.ParentId > 0)
                {
                    var parentMenu = await _menuRepository.GetByIdAsync(updateDto.ParentId.Value);
                    if (parentMenu == null || parentMenu.IsDeleted)
                    {
                        return ApiResponse<MenuDto>.Fail("父级菜单不存在");
                    }
                }

                _mapper.Map(updateDto, menu);
                menu.UpdateTime = DateTime.Now;

                await _menuRepository.UpdateAsync(menu);
                var menuDto = MapToDto(menu);
                return ApiResponse<MenuDto>.Success(menuDto, "更新菜单成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新菜单时发生异常，ID: {MenuId}", id);
                return ApiResponse<MenuDto>.Fail("更新菜单失败");
            }
        }

        /// <summary>
        /// 删除菜单
        /// </summary>
        /// <param name="id">菜单ID</param>
        /// <returns></returns>
        public async Task<ApiResponse<bool>> DeleteMenuAsync(int id)
        {
            try
            {
                var menu = await _menuRepository.GetByIdAsync(id);
                if (menu == null || menu.IsDeleted)
                {
                    return ApiResponse<bool>.Fail("菜单不存在");
                }

                // 检查是否有子菜单
                var hasChildren = await _menuRepository.ExistsAsync(m => !m.IsDeleted && m.ParentId == id);
                if (hasChildren)
                {
                    // 递归删除子菜单
                    await DeleteMenuRecursiveAsync(id);
                }
                else
                {
                    // 软删除菜单
                    menu.IsDeleted = true;
                    menu.UpdateTime = DateTime.Now;
                    await _menuRepository.UpdateAsync(menu);
                }

                return ApiResponse<bool>.Success(true, "删除菜单成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除菜单时发生异常，ID: {MenuId}", id);
                return ApiResponse<bool>.Fail("删除菜单失败");
            }
        }

        /// <summary>
        /// 批量删除菜单
        /// </summary>
        /// <param name="ids">菜单ID列表</param>
        /// <returns></returns>
        public async Task<ApiResponse<bool>> BatchDeleteMenusAsync(List<int> ids)
        {
            try
            {
                var successCount = 0;
                foreach (var id in ids)
                {
                    var result = await DeleteMenuAsync(id);
                    if (result.Code == 200) successCount++;
                }

                var message = $"批量删除完成，成功删除 {successCount}/{ids.Count} 个菜单";
                return ApiResponse<bool>.Success(true, message);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量删除菜单时发生异常");
                return ApiResponse<bool>.Fail("批量删除菜单失败");
            }
        }

        /// <summary>
        /// 更新菜单状态
        /// </summary>
        /// <param name="id">菜单ID</param>
        /// <param name="status">状态</param>
        /// <returns></returns>
        public async Task<ApiResponse<bool>> UpdateMenuStatusAsync(int id, int status)
        {
            try
            {
                var menu = await _menuRepository.GetByIdAsync(id);
                if (menu == null || menu.IsDeleted)
                {
                    return ApiResponse<bool>.Fail("菜单不存在");
                }

                menu.Status = status;
                menu.UpdateTime = DateTime.Now;
                
                await _menuRepository.UpdateAsync(menu);
                return ApiResponse<bool>.Success(true, "更新菜单状态成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新菜单状态时发生异常，ID: {MenuId}", id);
                return ApiResponse<bool>.Fail("更新菜单状态失败");
            }
        }

        /// <summary>
        /// 批量更新菜单状态
        /// </summary>
        /// <param name="ids">菜单ID列表</param>
        /// <param name="status">状态</param>
        /// <returns></returns>
        public async Task<ApiResponse<bool>> BatchUpdateMenuStatusAsync(List<int> ids, int status)
        {
            try
            {
                var menus = await _menuRepository.GetListAsync(m => !m.IsDeleted && ids.Contains(m.Id));

                foreach (var menu in menus)
                {
                    menu.Status = status;
                    menu.UpdateTime = DateTime.Now;
                    await _menuRepository.UpdateAsync(menu);
                }

                return ApiResponse<bool>.Success(true, "批量更新菜单状态成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量更新菜单状态时发生异常");
                return ApiResponse<bool>.Fail("批量更新菜单状态失败");
            }
        }

        /// <summary>
        /// 获取父级菜单选项
        /// </summary>
        /// <returns></returns>
        public async Task<ApiResponse<List<MenuDto>>> GetParentMenuOptionsAsync()
        {
            try
            {
                var menus = await _menuRepository.GetListAsync(m => !m.IsDeleted && m.Type != 3);
                var sortedMenus = menus.OrderBy(m => m.Sort).ToList();
                var menuDtos = sortedMenus.Select(MapToDto).ToList();
                return ApiResponse<List<MenuDto>>.Success(menuDtos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取父级菜单选项时发生异常");
                return ApiResponse<List<MenuDto>>.Fail("获取父级菜单选项失败");
            }
        }

        /// <summary>
        /// 检查菜单Key是否存在
        /// </summary>
        /// <param name="key">菜单Key</param>
        /// <param name="excludeId">排除的菜单ID</param>
        /// <returns></returns>
        public async Task<ApiResponse<bool>> CheckMenuKeyExistsAsync(string key, int? excludeId = null)
        {
            try
            {
                var exists = excludeId.HasValue 
                    ? await _menuRepository.ExistsAsync(m => !m.IsDeleted && m.Key == key && m.Id != excludeId.Value)
                    : await _menuRepository.ExistsAsync(m => !m.IsDeleted && m.Key == key);

                return ApiResponse<bool>.Success(exists);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查菜单Key是否存在时发生异常，Key: {Key}", key);
                return ApiResponse<bool>.Fail("检查菜单Key失败");
            }
        }

        #region 私有方法

        /// <summary>
        /// 递归删除菜单及其子菜单
        /// </summary>
        /// <param name="parentId">父级菜单ID</param>
        /// <returns></returns>
        private async Task DeleteMenuRecursiveAsync(int parentId)
        {
            var childMenus = await _menuRepository.GetListAsync(m => !m.IsDeleted && m.ParentId == parentId);
            
            foreach (var childMenu in childMenus)
            {
                await DeleteMenuRecursiveAsync(childMenu.Id);
                childMenu.IsDeleted = true;
                childMenu.UpdateTime = DateTime.Now;
                await _menuRepository.UpdateAsync(childMenu);
            }

            var parentMenu = await _menuRepository.GetByIdAsync(parentId);
            if (parentMenu != null)
            {
                parentMenu.IsDeleted = true;
                parentMenu.UpdateTime = DateTime.Now;
                await _menuRepository.UpdateAsync(parentMenu);
            }
        }

        /// <summary>
        /// 构建菜单树
        /// </summary>
        /// <param name="menus">菜单列表</param>
        /// <returns></returns>
        private List<MenuDto> BuildMenuTree(IEnumerable<Menu> menus)
        {
            var menuDtos = menus.Select(MapToDto).ToList();
            return BuildMenuTree(menuDtos);
        }

        /// <summary>
        /// 构建菜单树
        /// </summary>
        /// <param name="menuDtos">菜单DTO列表</param>
        /// <returns></returns>
        private List<MenuDto> BuildMenuTree(List<MenuDto> menuDtos)
        {
            var rootMenus = menuDtos.Where(m => m.ParentId == null || m.ParentId == 0).ToList();
            
            foreach (var rootMenu in rootMenus)
            {
                BuildMenuChildren(rootMenu, menuDtos);
            }
            
            return rootMenus.OrderBy(m => m.Sort).ToList();
        }

        /// <summary>
        /// 构建菜单子项
        /// </summary>
        /// <param name="parentMenu">父级菜单</param>
        /// <param name="allMenus">所有菜单</param>
        private void BuildMenuChildren(MenuDto parentMenu, List<MenuDto> allMenus)
        {
            var children = allMenus.Where(m => m.ParentId == parentMenu.Id).OrderBy(m => m.Sort).ToList();
            parentMenu.Children = children;
            
            foreach (var child in children)
            {
                BuildMenuChildren(child, allMenus);
            }
        }

        /// <summary>
        /// 将Menu实体映射为MenuDto
        /// </summary>
        /// <param name="menu">菜单实体</param>
        /// <returns></returns>
        private MenuDto MapToDto(Menu menu)
        {
            // 使用AutoMapper进行对象映射
            return _mapper.Map<MenuDto>(menu);
        }

        #endregion
    }
}